package com.tangruojie.controller;

import com.tangruojie.domain.ResponseCode;
import com.tangruojie.domain.ResponseResult;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping
public class HelloController {

    /**
     * Spring Security 的 方法级注解（@PreAuthorize、@Secured 等）默认是关闭的。
     * - @EnableMethodSecurity(prePostEnabled = true)  // 开启 @PreAuthorize/@PostAuthorize
     */

    /**
     * - @PreAuthorize 抛出的异常不会走 AccessDeniedHandler
     * URL 级权限（authorizeHttpRequests / FilterSecurityInterceptor）被拒绝时，异常在 过滤器链 内部产生，才会被 ExceptionTranslationFilter 转给你配置的：
     * 401 → AuthenticationEntryPoint
     * 403 → AccessDeniedHandler
     * 但 方法级注解（@PreAuthorize）的拒绝，是在 方法调用的 AOP 层抛出的 AccessDeniedException，不在过滤器链里，AccessDeniedHandler 接收不到，最终会一路冒泡到 MVC 层，被你的全局异常处理器（或默认机制）当作普通异常处理——常见结果就是 500。
     */

    /**
     * 维度	        URL 级（authorizeHttpRequests）	                            方法级（@PreAuthorize/@PostAuthorize/@Secured）
     * 触发时机	    过滤器链阶段，在进入控制器之前	                                 AOP 阶段，在调用方法（Controller/Service）时
     * 适用粒度	    路径/模块维度的粗粒度访问控制	                                细粒度业务规则、对象级/参数级检查
     * 性能	        更早拦截 → 性能友好	                                        稍晚拦截；可结合业务数据判断
     * 可见性	    规则集中、全局一览	                                            分散在代码处，贴近业务语义
     * 典型场景	    公开/受限模块分区、静态资源放行、健康检查、Swagger、/admin/**	    “只能看自己的资源”“只能修改自己创建的单据”“多条件表达式/SpEL”
     * 易踩坑	    写了 .anyRequest().permitAll() 覆盖了限制	                    需开启 @EnableMethodSecurity；自调用不走代理；异常不走 AccessDeniedHandler
     */

    /**
     * Spring Security 中的落地方式
     * 都放进 authorities：
     * 角色：存成 ROLE_admin、ROLE_user
     * 权限：存成 sys:user:query 等字符串
     * 校验时用不同的表达式：
     * 角色：hasRole("admin") / hasAnyRole("admin","user")
     * 权限：hasAuthority("sys:user:query") / hasAnyAuthority(...)
     */

    @GetMapping("/hello")
    @PreAuthorize("hasRole('admin')")
    public ResponseResult hello() {
        return new ResponseResult(
                ResponseCode.GET_SUCCESS,
                "查询成功",
                "hello world!"
        );
    }

}
